#include  "board.h"
#include  "Typedef.h"
#include  "hal_int.h"
#include  "hal_mcu.h" 
#include  "hal_uart.h"

//----------------------------------------------------------------------------------
// hal_uart.c extern macro define
//----------------------------------------------------------------------------------
#define RXB8            1
#define TXB8            0
#define UPE             2
#define OVR             3
#define FE              4
#define UDRE            5
#define RXC             7

#define FRAMING_ERROR         (1<<FE)
#define PARITY_ERROR          (1<<UPE)
#define DATA_OVERRUN          (1<<OVR)
#define DATA_REGISTER_EMPTY   (1<<UDRE)
#define RX_COMPLETE           (1<<RXC)

#define    UART_RX_BUFFER_SIZE      (20)
#define    UART_TX_BUFFER_SIZE      (20)


//----------------------------------------------------------------------------------
// hal_uart.c static variables define
//----------------------------------------------------------------------------------


static  volatile INT8U rx_buffer[UART_RX_BUFFER_SIZE];  // USART0 Receiver buffer
static  volatile INT8U rx_wr_index=0;
static  volatile INT8U rx_rd_index=0;
static  volatile INT8U rx_counter=0;
static  volatile INT8U rx_buffer_overflow=0; // This flag is set on USART Receiver buffer overflow



static  volatile INT8U tx_buffer[UART_TX_BUFFER_SIZE];    // USART0 Transmitter buffer
static  volatile INT8U tx_wr_index=0;
static  volatile INT8U tx_rd_index=0;
static  volatile INT8U tx_counter=0;


//----------------------------------------------------------------------------------
//  void  usart_init(INT32U Baud)
//
//  DESCRIPTION:
//    Initialize the USART:
//      1.Set USART work as UART , transmit rate as parameter Baud reference
//
//  ARGUMENTS:
//    Baud  -  The baudrate of UART
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
void  usart_init(INT32U Baud)
{
   /*
   UCSRB = 0x00; //disable while setting baud rate
   UCSRA|= 1<<U2X;
   UBRRL = (((CPU_OSC/Baud)/8-1)%256);
   UBRRH = (((CPU_OSC/Baud)/8-1)/256);
   
   // Enable receiver and transmitter 
   UCSRB = (1<<RXEN)|(1<<TXEN);
   // Set frame format: 8data, 1stop bit 
   UCSRC = (1<<URSEL)|(3<<UCSZ0);
   */
   UCSRB = 0x00; //disable while setting baud rate
   UCSRA|= 1<<U2X;
   UCSRC = 0x86;
   UBRRL = (((CPU_OSC/Baud)/8-1)%256);
   UBRRH = (((CPU_OSC/Baud)/8-1)/256);
   UCSRB = 0xD8;
}


//----------------------------------------------------------------------------------
//  void usart_rx_isr(void)
//
//  DESCRIPTION:
//    USART Receiver interrupt service routine
//
//  ARGUMENTS:
//    None
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
#pragma vector=USART_RXC_vect
__interrupt  void usart_rx_isr(void)
{
  INT8U status,data;

  status=UCSRA;
  data=UDR;
  if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
    {
        rx_buffer[rx_wr_index]=data;
        if (++rx_wr_index == UART_RX_BUFFER_SIZE) rx_wr_index=0;
        if (++rx_counter == UART_RX_BUFFER_SIZE)
            {
              rx_counter=0;
              rx_buffer_overflow=1;
            }
    }
}

//----------------------------------------------------------------------------------
//  INT8U usart_getchar(void)
//
//  DESCRIPTION:
//    Get a character from the USART Receiver buffer
//
//  ARGUMENTS:
//    None  -  The baudrate of UART
//
//  RETURNS:
//    data  -  A character get from the RX buffer
//----------------------------------------------------------------------------------
INT8U usart_getchar(void)
{
    /*
    while ( !(UCSRA & (1<<RXC)) )
    ;
    return UDR;
    */
    INT8U data;
    while(rx_counter==0);
    data=rx_buffer[rx_rd_index];
    if (++rx_rd_index== UART_RX_BUFFER_SIZE) rx_rd_index=0;
    HAL_INT_OFF();
    --rx_counter;
    HAL_INT_ON();
    return data; 
}

//----------------------------------------------------------------------------------
//  INT8U usart_ischarinrxfifo(void)
//
//  DESCRIPTION:
//    Return the number of character in the USART Receiver buffer
//
//  ARGUMENTS:
//    None  -  The baudrate of UART
//
//  RETURNS:
//    rx_counter  -  Indicate the number of character in the USART Receiver buffer
//----------------------------------------------------------------------------------
INT8U usart_ischarinrxfifo(void)
{
    return rx_counter;
}

//----------------------------------------------------------------------------------
//  void usart_tx_isr(void)
//
//  DESCRIPTION:
//    USART Transmitter interrupt service routine
//
//  ARGUMENTS:
//    None
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
#pragma vector=USART_TXC_vect
__interrupt  void usart_tx_isr(void)
{
  if (tx_counter)
    {
      --tx_counter;
      UDR=tx_buffer[tx_rd_index];
      if (++tx_rd_index == UART_TX_BUFFER_SIZE) tx_rd_index=0;
    };
}


//----------------------------------------------------------------------------------
//  void usart_putchar(INT8U data)
//
//  DESCRIPTION:
//    Write a character to the USART Transmitter buffer
//
//  ARGUMENTS:
//    data  -  The write character
//
//  RETURNS:
//    None  
//----------------------------------------------------------------------------------
void usart_putchar(INT8U data)
{
    /*
    // Wait for empty transmit buffer 
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    // Put data into buffer, sends the data 
    UDR = data;
   */
    while (tx_counter == UART_TX_BUFFER_SIZE);
    HAL_INT_OFF();
    if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
      {
        tx_buffer[tx_wr_index]=data;
        if (++tx_wr_index == UART_TX_BUFFER_SIZE) tx_wr_index=0;
        ++tx_counter;
      }
    else
        UDR=data;
   HAL_INT_ON();
}

//----------------------------------------------------------------------------------
//  void uart_write_line(const char *string)
//
//  DESCRIPTION:
//    Write a string to the USART Transmitter buffer
//
//  ARGUMENTS:
//    string  -  Pointer to the string
//
//  RETURNS:
//    None  
//----------------------------------------------------------------------------------
void uart_write_line(const char *string)
{
  while (*string != '\0')
    usart_putchar(*string++);
}

//----------------------------------------------------------------------------------
//  int usart_get_echo_line(void)
//
//  DESCRIPTION:
//    Get a line input for the USART terminal 
//
//  ARGUMENTS:
//    None  
//
//  RETURNS:
//    retval  -  the character get from USART terminal
//----------------------------------------------------------------------------------
int usart_get_echo_line(void)
{
  int rx_char;
  int retval = USART_SUCCESS;

  while (1)
  {
    rx_char = usart_getchar();
    if (rx_char == USART_FAILURE)
    {
      usart_write_line("Error!!!\n");
      break;
    }
    if (rx_char == '\x03')
    {
      retval = USART_FAILURE;
      break;
    }
    usart_putchar(rx_char);
    if (rx_char == '\r')
    {
      usart_putchar('\n');
      break;
    }
  }

  return retval;
}